# -*- coding:utf-8 -*-

# @Time    : 2018/9/30 11:19 AM

# @Author  : Swing


import pandas as pd
from sklearn.model_selection import train_test_split, KFold, GridSearchCV
from sklearn.linear_model import LinearRegression, Ridge, Lasso, RidgeCV
from sklearn.metrics import r2_score, SCORERS
from sklearn.metrics import mean_squared_error
import matplotlib.pyplot as plt
import numpy as np


def training(data):
    y = data['cnt'].values
    x = data.drop('cnt', axis=1)

    columns = x.columns

    """
    将数据分割为训练数据和测试数据
    随机取20%的数据构建测试样本,其余作为训练样本
    """
    x_train, x_test, y_train, y_test = train_test_split(x, y, random_state=33, test_size=0.2)
    print(x_train.shape)

    # 线性回归模型

    # 使用默认参数初始化
    lr = LinearRegression()

    # 训练模型参数
    lr.fit(x_train, y_train)

    # 预测
    y_test_pred_lr = lr.predict(x_test)
    y_train_pred_lr = lr.predict(x_train)

    # 看看各特征的权重系数，系数的绝对值大小可视为该特征的重要性
    fs = pd.DataFrame({"columns": list(columns), "coef": list((lr.coef_.T))})
    fs.sort_values(by=['coef'], ascending=False)

    # 查看各特征的权重系数, 系数的绝对值大小可以视为该特征的重要性
    # fs = pd.DataFrame({"columns": list(columns), "coef": list((lr.coef_.T))})
    # fs.sort_values(by=['coef'], ascending=False)
    print(fs)

    # 使用r2_score评价模型在测试机和训练集上的性能, 并输出评估结果
    print('The r2 score of LinerRegression on test is', r2_score(y_test, y_test_pred_lr))
    print('The r2 score of LinerRegression on train is', r2_score(y_train, y_train_pred_lr))

    # 使用RMSE评价模型在测试机和训练集上的性能, 并输出评估结果
    print('The RMSE of LinerRegression on test is', np.sqrt(mean_squared_error(y_test, y_test_pred_lr)))
    print('The RMSE of LinerRegression on train is', np.sqrt(mean_squared_error(y_train, y_train_pred_lr)))

    # 在训练集上观察预测残差的分布, 看是否符合模型假设: 噪声为0均值的高斯噪声
    # f, ax = plt.subplots(figsize=(7, 5))
    # f.tight_layout()
    # ax.hist(y_train - y_train_pred_lr, bins=40, label='Residuals Linear', color='b', alpha=.5);
    # ax.set_title("Histogram of Residuals")
    # ax.legend(loc='best')

    # plt.show()

    # 真值和预测值的散点图
    # plt.figure(figsize=(4, 3))
    # plt.scatter(y_train, y_train_pred_lr)
    # plt.plot([-3, 3], [-3, 3], '--k')
    # plt.axis('tight')
    # plt.xlabel('True cnt')
    # plt.ylabel('Predicted price')
    # plt.tight_layout()
    # plt.show()

    """
    岭回归
    815.7462970064079
    805.2846720234812
    """

    # 805.2863188101418
    # 805.2854750727812
    # 805.2846882944184

    # 设置超参数范围
    alphas = [0.0001, 0.001, 0.01, 0.1, 1, 10, 100]
    # alphas = np.linspace(0, 0.0001, 100)
    ridge = RidgeCV(alphas=alphas, cv=5,  store_cv_values=False)
    ridge.fit(x_train, y_train)
    # ridge = Ridge(fit_intercept=False)
    # kfold = KFold(n_splits=5)
    # grade_param = {"alpha": alphas}
    # grid = GridSearchCV(estimator=ridge, param_grid=grade_param, cv=kfold, scoring='neg_mean_squared_error')
    #
    # grid.fit(x_train, y_train)
    # grid.predict
    # # 2.0202020202020203e-05
    # # print(grid.)
    # print('The RMSE of RidgeCV on test is ', np.sqrt(0-grid.best_score_))
    # print('Best param ', grid.best_params_)

    # return

    y_test_pred_ridge = ridge.predict(x_test)
    y_train_pred_ridge = ridge.predict(x_train)

    # 使用r2_score评价模型在测试集和训练集上的性能
    print('The r2 score of RidgeCV on test is', r2_score(y_test, y_test_pred_ridge))
    print('The r2 score of RidgeCV on train is', r2_score(y_train, y_train_pred_ridge))

    # 使用RMSE评价模型在测试机和训练集上的性能, 并输出评估结果
    print('The RMSE of RidgeCV on test is', np.sqrt(mean_squared_error(y_test, y_test_pred_lr)))
    print('The RMSE of RidgeCV on train is', np.sqrt(mean_squared_error(y_train, y_train_pred_lr)))

    print('alpha ', ridge.alpha_)

    # smallest_idx = ridge.cv_values_.mean(axis=0).argmin()
    # print(smallest_idx)

    return

    """
    lasso回归
    """
    # lasso_alphas = [0.001, 0.01, 0.1, 1, 10, 100]
    # lasso = LassoCV(alphas=alphas, cv=5,  fit_intercept=False, max_iter=200000)
    lasso = Lasso(fit_intercept=False, max_iter=100000000)
    # lasso.fit(x_train, y_train)

    lasso_grid = GridSearchCV(estimator=lasso, cv=kfold, scoring='neg_mean_squared_error', param_grid=grade_param)
    lasso_grid.fit(x_train, y_train)

    print('The RMSE of Lasso on test is ', np.sqrt(0 - lasso_grid.best_score_))
    print('Lasso best param ', lasso_grid.best_params_)


